#pragma once

#include <iostream>
#include <string>

#ifdef __APPLE__ 
#include <json/json.h> 
#endif
#ifdef __linux__
#include <jsoncpp/json/json.h>
#endif
#include "inetapi.hpp"

namespace proto
{
struct request
{
    request() 
    {}
    request(int x, char op, int y) : _x(x), _y(y), _op(op) 
    {}

// #define SERIAL_BY_MYSELF

#ifdef SERIAL_BY_MYSELF
    std::string serialize() 
    {
        std::string s = std::to_string(_x) + ' ' + _op + ' ' + std::to_string(_y);
        return std::to_string(s.size()) + '\n' + s + '\n';
    }

    void deserialize(const std::string& req)
    {
        int pos = req.find('\n', 0);
        if (pos == std::string::npos)
            return;
        pos += 1;

        int pos1 = req.find(' ', pos);
        _x = std::stoi(req.substr(pos, pos1));
        pos1 += 1;
        _op = req[pos1];
        pos1 += 1;
        _y = std::stoi(req.substr(pos1, req.size() - 1 - pos1));
    }

    static std::string recvpack(int sock)
    {
        std::string msg;

        bool flg = false;
        while (true)
        {
            char ch;
            inet::api::Recv(sock, &ch, sizeof(ch));

            msg.push_back(ch);

            if (ch == '\n')
            {
                if (flg) break;
                else flg = true;
            }
        }

        return msg;
    }

#else

    std::string serialize() 
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["op"] = _op;
        return Json::FastWriter().write(root);
    }

    void deserialize(const std::string& req)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(req, root);
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _op = (char)root["op"].asInt();
    }

    static std::string recvpack(int sock)
    {
        std::string msg;
        while (true)
        {
            char ch;
            inet::api::Recv(sock, &ch, sizeof(ch));
            msg.push_back(ch);
            if (ch == '\n') break;
        }
        return msg;
    }

#endif

    int _x, _y;
    char _op;
};

struct response
{
    response()
    {}
    response(int res, int st) : _res(res), _st(st) 
    {}

#ifdef SERIAL_BY_MYSELF
    std::string serialize() 
    {
        std::string s = std::to_string(_res) + ' ' + std::to_string(_st);
        return std::to_string(s.size()) + '\n' + s + '\n';
    }

    void deserialize(const std::string& rsp)
    {
        int posn = rsp.find('\n', 0);
        if (posn == std::string::npos)
            return;
        posn += 1;

        int pos = rsp.find(' ', posn);
        _res = std::stoi(rsp.substr(posn, pos));
        pos += 1;
        _st = std::stoi(rsp.substr(pos, rsp.size() - 1 - pos));
    }

    static std::string recvpack(int sock)
    {
        std::string msg;

        bool flg = false;
        while (true)
        {
            char ch;
            inet::api::Recv(sock, &ch, sizeof(ch));

            msg.push_back(ch);

            if (ch == '\n')
            {
                if (flg) break;
                else flg = true;
            }
        }
        return msg;
    }
#else

    std::string serialize() 
    {
        Json::Value root;
        root["res"] = _res;
        root["st"] = _st;
        return Json::FastWriter().write(root);
    }

    void deserialize(const std::string& rsp)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(rsp, root);
        _res = root["res"].asInt();
        _st = root["st"].asInt();
    }

    static std::string recvpack(int sock)
    {
        std::string msg;
        while (true)
        {
            char ch;
            inet::api::Recv(sock, &ch, sizeof(ch));
            msg.push_back(ch);
            if (ch == '\n') break;
        }
        return msg;
    }
#endif

    int _res, _st;
};
}
